﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.Shell;
using Gauss.Isp.Attributes;
using System.ComponentModel;
using System.Windows.Forms.Design;
using System.Drawing.Design;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
using Microsoft.VisualStudio.Shell.Interop;
using EnvDTE80;
using Microsoft.Win32;

namespace Gauss.Isp
{
    /// <summary>
    /// This class adds the ISP option to the Tools -> Options pane.
    /// </summary>
    public class ToolsOptions : DialogPage
    {
        #region Member Variables

        private bool _showIspCompileDialog;
        private bool _useIssueOrder;
        private string _ispExecutablePath;
        private string _ispHeaderPath;
        private string _ispLibraryPath;
        private string _ispDebugCodePath;
        private string _ispUiPath;
        private string _javaPath;
        private string _mpishimPath;
        private string _mpiDotNET_ISP_Path;
        private string _ispDLLPath;
        private int _ispPort;
        private bool _ispUseBlockingSends;
        private int _ispReportProgress;
        private bool _ispFib;
        //private bool _ispOpenMP;
        private bool _ispMpicalls;
        private bool _verboseMode;
        private bool _progOutOnly;
        private string _expMode = "all";
        private int _expSome;
        private bool _boundMix;
        //private bool _focusPlus;
        private bool _ampleSetFixDisable;

        #endregion

        #region Properties

        [LocalizedCategory("ToolsOptions_Category_General")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_ShowIspCompileDialog")]
        [LocalizedDescription("ToolsOptions_Description_ShowIspCompileDialog")]
        [DefaultValue(true)]
        public bool ShowIspCompileDialog
        {
            get { return _showIspCompileDialog; }
            set { _showIspCompileDialog = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_General")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_UseIssueOrder")]
        [LocalizedDescription("ToolsOptions_Description_UseIssueOrder")]
        [DefaultValue(true)]
        public bool UseIssueOrder
        {
            get { return _useIssueOrder; }
            set { _useIssueOrder = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_Paths")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspExecutablePath")]
        [LocalizedDescription("ToolsOptions_Description_IspExecutablePath")]
        [EditorAttribute(typeof(IspExecutableBrowser), typeof(UITypeEditor))]
        [DefaultValue("")]
        public string IspExecutablePath
        {
            get { return _ispExecutablePath; }
            set { _ispExecutablePath = value; }
        }

        
        [LocalizedCategory("ToolsOptions_Category_Paths")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspMPIdotNETLibraryPath")]
        [LocalizedDescription("ToolsOptions_Description_IspMPIdotNETLibraryPath")]
        [EditorAttribute(typeof(MpiNetISPBrowser), typeof(UITypeEditor))]
        [DefaultValue("")]
        public string MPIdotNET_ISP_Path
        {
            get { return _mpiDotNET_ISP_Path; }
            set { _mpiDotNET_ISP_Path = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_Paths")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspLibraryPath")]
        [LocalizedDescription("ToolsOptions_Description_IspLibraryPath")]
        [EditorAttribute(typeof(IspLibraryBrowser), typeof(UITypeEditor))]
        [DefaultValue("")]
        public string IspLibraryPath
        {
            get { return _ispLibraryPath; }
            set { _ispLibraryPath = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_Paths")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspDLLPath")]
        [LocalizedDescription("ToolsOptions_Description_IspDLLPath")]
        [EditorAttribute(typeof(IspDllBrowser), typeof(UITypeEditor))]
        [DefaultValue("")]
        public string IspDLLPath
        {
            get { return _ispDLLPath; }
            set { _ispDLLPath = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_Paths")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspDebugCodePath")]
        [LocalizedDescription("ToolsOptions_Description_IspDebugCodePath")]
        [EditorAttribute(typeof(IspDebugCodeBrowser), typeof(UITypeEditor))]
        [DefaultValue("")]
        public string IspDebugCodePath
        {
            get { return _ispDebugCodePath; }
            set { _ispDebugCodePath = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_Paths")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspHeaderPath")]
        [LocalizedDescription("ToolsOptions_Description_IspHeaderPath")]
        [EditorAttribute(typeof(IspHeaderBrowser), typeof(UITypeEditor))]
        [DefaultValue("")]
        public string IspHeaderPath
        {
            get { return _ispHeaderPath; }
            set { _ispHeaderPath = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_Paths")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspUiPath")]
        [LocalizedDescription("ToolsOptions_Description_IspUiPath")]
        [EditorAttribute(typeof(IspUiBrowser), typeof(UITypeEditor))]
        [DefaultValue("")]
        public string IspUiPath
        {
            get { return _ispUiPath; }
            set { _ispUiPath = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_Paths")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_JavaPath")]
        [LocalizedDescription("ToolsOptions_Description_JavaPath")]
        [EditorAttribute(typeof(JavaBrowser), typeof(UITypeEditor))]
        [DefaultValue("")]
        public string JavaPath
        {
            get { return _javaPath; }
            set { _javaPath = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_Paths")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_MpishimPath")]
        [LocalizedDescription("ToolsOptions_Description_MpishimPath")]
        [EditorAttribute(typeof(MpishimBrowser), typeof(UITypeEditor))]
        [DefaultValue("")]
        public string MpishimPath
        {
            get { return _mpishimPath; }
            set { _mpishimPath = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_AmpleSetFix")]
        [LocalizedDescription("ToolsOptions_Description_AmpleSetFix")]
        [DefaultValue(false)]
        public bool AmpleSetFixDisable
        {
            get { return _ampleSetFixDisable; }
            set { _ampleSetFixDisable = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspPort")]
        [LocalizedDescription("ToolsOptions_Description_IspPort")]
        [DefaultValue(9999)]
        public int IspPort
        {
            get { return (_ispPort < 0) ? 0 : _ispPort; }
            set { _ispPort = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspBlockingSends")]
        [LocalizedDescription("ToolsOptions_Description_IspBlockingSends")]
        [DefaultValue(true)]
        public bool IspBlockingSends
        {
            get { return _ispUseBlockingSends; }
            set { _ispUseBlockingSends = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspReportProgress")]
        [LocalizedDescription("ToolsOptions_Description_IspReportProgress")]
        [DefaultValue(0)]
        public int IspReportProgress
        {
            get { return _ispReportProgress; }
            set { _ispReportProgress = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspFib")]
        [LocalizedDescription("ToolsOptions_Description_IspFib")]
        [DefaultValue(true)]
        public bool IspFib
        {
            get { return _ispFib; }
            set { _ispFib = value; }
        }

        //openmp not currently being enabled in build
        //[LocalizedCategory("ToolsOptions_Category_IspOptions")]
        //[LocalizedDisplayName("ToolsOptions_DisplayName_IspOpenMP")]
        //[LocalizedDescription("ToolsOptions_Description_IspOpenMP")]
        //[DefaultValue(false)]
        //public bool IspOpenMP
        //{
        //    get { return _ispOpenMP; }
        //    set { _ispOpenMP = value; }
        //}

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_IspMpicalls")]
        [LocalizedDescription("ToolsOptions_Description_IspMpicalls")]
        [DefaultValue(false)]
        public bool ISPMpicalls
        {
            get { return _ispMpicalls; }
            set { _ispMpicalls = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_Verbose")]
        [LocalizedDescription("ToolsOptions_Description_Verbose")]
        [DefaultValue(true)]
        public bool VerboseMode
        {
            get { return _verboseMode; }
            set { _verboseMode = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_ProgOutOnly")]
        [LocalizedDescription("ToolsOptions_Description_ProgOutOnly")]
        [DefaultValue(false)]
        public bool ProgOutOnly
        {
            get { return _progOutOnly; }
            set { _progOutOnly = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_ExpMode")]
        [LocalizedDescription("ToolsOptions_Description_ExpMode")]
        [DefaultValue("all")]
        public string ExpMode
        {
            get { return _expMode; }
            set
            {
                if (value.ToLower() == "all" ||
                  value.ToLower() == "random" ||
                  value.ToLower() == "left_most")
                    _expMode = value.ToLower();
            }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_ExpSome")]
        [LocalizedDescription("ToolsOptions_Description_ExpSome")]
        [DefaultValue(0)]
        public int ExpSome
        {
            get { return _expSome; }
            set { _expSome = value; }
        }

        [LocalizedCategory("ToolsOptions_Category_IspOptions")]
        [LocalizedDisplayName("ToolsOptions_DisplayName_BoundMix")]
        [LocalizedDescription("ToolsOptions_Description_BoundMix")]
        [DefaultValue(false)]
        public bool BoundMix
        {
            get { return _boundMix; }
            set { _boundMix = value; }
        }

        //Don't know what this option does -- waiting for WeiFan's synopsis (i.e. a production-ready feature?)
        //[LocalizedCategory("ToolsOptions_Category_IspOptions")]
        //[LocalizedDisplayName("ToolsOptions_DisplayName_FocusPlus")]
        //[LocalizedDescription("ToolsOptions_Description_FocusPlus")]
        //[DefaultValue(false)]
        //public bool FocusPlus
        //{
        //    get { return _focusPlus; }
        //    set { _focusPlus = value; }
        //}
        
        [Browsable(false)]
        public FileInfo Get_MPIdotNET_ISP_Path
        {
            get
            {
                string path = MPIdotNET_ISP_Path;
                if (path != null && File.Exists(path))
                    return new FileInfo(path);
                return FindFilePath("MPI.dll");
            }
        }

        [Browsable(false)]
        public string Get_IspDllDirectory
        {
            get
            {
                return GetInstallDirectory;
            }
        }

        [Browsable(false)]
        public FileInfo Get_IspExecutablePath
        {
            get
            {
                string path = IspExecutablePath;
                if (path != null && File.Exists(path))
                    return new FileInfo(path);
                return FindFilePath("isp.exe");
            }
        }

        [Browsable(false)]
        public FileInfo Get_IspLibraryPath
        {
            get
            {
                string path = IspLibraryPath;
                if (path != null && File.Exists(path))
                    return new FileInfo(path);
                return FindFilePath("isp.lib");
            }
        }

        [Browsable(false)]
        public FileInfo Get_IspDebugCodePath
        {
            get
            {
                string path = IspDebugCodePath;
                if (path != null && File.Exists(path))
                    return new FileInfo(path);
                return FindFilePath("isp_debug.c");
            }
        }

        [Browsable(false)]
        public FileInfo Get_IspHeaderPath
        {
            get
            {
                string path = IspHeaderPath;
                if (path != null && File.Exists(path))
                    return new FileInfo(path);
                return FindFilePath("isp.h");
            }
        }

        [Browsable(false)]
        public FileInfo Get_IspUiPath
        {
            get
            {
                string path = IspUiPath;
                if (path != null && File.Exists(path))
                    return new FileInfo(path);
                return FindFilePath("ispui.jar");
            }
        }

        [Browsable(false)]
        public string Get_JavaPath
        {
            get
            {
                string path = JavaPath;
                if (!string.IsNullOrEmpty(path))
                    return path;
                return "java";
            }
        }

        [Browsable(false)]
        public string Get_MpishimPath
        {
            get
            {
                string path = MpishimPath;
                if (!string.IsNullOrEmpty(path))
                    return path;

                try
                {
                    DTE2 dte = IspPackage.GetGlobalService(typeof(SDTE)) as DTE2;
                    List<string> possiblePaths = new List<string>();
                    possiblePaths.Add(Path.Combine(new FileInfo(dte.FullName).Directory.FullName, "Remote Debugger"));
                    possiblePaths.Add(Path.Combine(new FileInfo(dte.FullName).Directory.FullName.Replace(" (x86)", ""), "Remote Debugger"));

                    StringBuilder sb = new StringBuilder();
                    foreach (string p in possiblePaths)
                    {
                        string rdPath = Path.Combine(Path.Combine(p, "x86"), "mpishim.exe");
                        if (File.Exists(rdPath))
                        {
                            return rdPath;
                        }
                        sb.AppendFormat("{0}\n", path);
                    }
                }
                catch { }

                return "mpishim";
            }
        }

        private string GetInstallDirectory
        {
            get{
                RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\GaussGroup\ISP");
                if (key != null && key.GetValue("InstallLocation") != null)
                {
                    return (string)key.GetValue("InstallLocation");
                }else{
                    return string.Empty;
                }
            }
            set{}
        }

        //this is called when one of the public properties for paths is null or doesn't exist 
        private FileInfo FindFilePath(string file)
        {
            //broke this by installing isp.dll (plugin) in $VSINSTALL\Common7\Packages
            //FileInfo assembly = new FileInfo(Assembly.GetExecutingAssembly().Location);
            //FileInfo path = new FileInfo(Path.Combine(assembly.Directory.FullName, file));
            FileInfo retVal = null;
            string installDir = GetInstallDirectory;
            if (installDir != string.Empty)
            {
                FileInfo path = new FileInfo(Path.Combine(installDir, file));
                if (path.Exists)
                {
                    retVal = path;
                }
            }
            return retVal;
        }

        #endregion

        public ToolsOptions()
        {
            this._showIspCompileDialog = true;
            this._useIssueOrder = true;
            this._ispPort = 9999;
            this._ispFib = true;
        }

        internal class DropDownEditor : UITypeEditor
        {
            private string _fileFilter;
            private string _defaultString;

            public DropDownEditor(string fileFilter, string defaultString)
            {
                this._fileFilter = fileFilter;
                this._defaultString = defaultString;
            }

            public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
            {
                return UITypeEditorEditStyle.Modal;
            }

            public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
            {
                IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
                if (editorService == null)
                {
                    return base.EditValue(context, provider, value);
                }

                using (OpenFileDialog dialog = new OpenFileDialog())
                {
                    dialog.FileName = (value == null) ? "" : value as string;
                    dialog.Filter = _fileFilter;
                    dialog.Multiselect = false;
                    dialog.CheckFileExists = true;
                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        return dialog.FileName;
                    }
                }
                
                return base.EditValue(context, provider, value);
            }
        }

        internal class IspExecutableBrowser : DropDownEditor
        {
            public IspExecutableBrowser() : base("isp.exe|isp.exe", null) { }
        }

        internal class IspHeaderBrowser : DropDownEditor
        {
            public IspHeaderBrowser() : base("isp.h|isp.h", null) { }
        }

        internal class MpiNetISPBrowser : DropDownEditor
        {
            public MpiNetISPBrowser() : base("MPI.dll|Mpi.dll", null) { }
        }

        internal class IspDllBrowser : DropDownEditor
        {
            public IspDllBrowser() : base("isp.dll|isp.dll", null) { }
        }

        internal class IspLibraryBrowser : DropDownEditor
        {
            public IspLibraryBrowser() : base("isp.lib|isp.lib", null) { }
        }

        internal class IspDebugCodeBrowser : DropDownEditor
        {
            public IspDebugCodeBrowser() : base("isp_debug.c|isp_debug.c", null) { }
        }

        internal class IspUiBrowser : DropDownEditor
        {
            public IspUiBrowser() : base("ispui.jar|ispui.jar", null) { }
        }

        internal class JavaBrowser : DropDownEditor
        {
            public JavaBrowser() : base("java.exe|java.exe", null) { }
        }

        internal class MpishimBrowser : DropDownEditor
        {
            public MpishimBrowser() : base("mpishim.exe|mpishim.exe", null) { }
        }

        internal class JgraphBrowser : DropDownEditor
        {
            public JgraphBrowser() : base("jgraph.jar|jgraph.jar", null) { }
        }
    }
}
